// ============================================
// internal/service/migration_service.go
// ============================================

package service

import (
	"context"
	"fmt"
	"sync"
	"time"

	"github.com/google/uuid"
	"github.com/sirupsen/logrus"
	"libvirt.org/go/libvirt"

	"virt-manager-go/internal/domain"
)

type migrationService struct {
	connMgr domain.ConnectionManager
	logger  *logrus.Logger

	// 迁移任务跟踪
	jobs   map[string]*domain.MigrationJob
	jobsMu sync.RWMutex
}

func NewMigrationService(connMgr domain.ConnectionManager, logger *logrus.Logger) domain.MigrationService {
	return &migrationService{
		connMgr: connMgr,
		logger:  logger,
		jobs:    make(map[string]*domain.MigrationJob),
	}
}

// MigrateVM 迁移虚拟机
func (s *migrationService) MigrateVM(ctx context.Context, srcConnID, vmName, destURI string, config *domain.MigrationConfig) (*domain.MigrationJob, error) {
	s.logger.WithFields(logrus.Fields{
		"vm":       vmName,
		"dest_uri": destURI,
		"live":     config.Live,
	}).Info("Starting VM migration")

	// 获取源连接
	srcConn, err := s.connMgr.GetConnection(srcConnID)
	if err != nil {
		return nil, fmt.Errorf("failed to get source connection: %w", err)
	}

	// 查找虚拟机
	dom, err := srcConn.LookupDomainByName(vmName)
	if err != nil {
		return nil, fmt.Errorf("VM not found: %w", err)
	}
	defer dom.Free()

	// 创建迁移任务
	jobID := uuid.New().String()
	srcURI, _ := srcConn.GetURI()

	job := &domain.MigrationJob{
		ID:        jobID,
		VMName:    vmName,
		SourceURI: srcURI,
		DestURI:   destURI,
		Status:    domain.MigrationStatusPending,
		StartTime: time.Now(),
	}

	s.jobsMu.Lock()
	s.jobs[jobID] = job
	s.jobsMu.Unlock()

	// 异步执行迁移
	go s.performMigration(ctx, dom, destURI, config, job)

	return job, nil
}

// performMigration 执行迁移
func (s *migrationService) performMigration(ctx context.Context, dom *libvirt.Domain, destURI string, config *domain.MigrationConfig, job *domain.MigrationJob) {
	// 更新状态为运行中
	s.updateJobStatus(job.ID, domain.MigrationStatusRunning, nil)

	// 构建迁移标志
	flags := s.buildMigrationFlags(config)

	// 设置迁移参数
	params := &libvirt.DomainMigrateParameters{}
	if config.Bandwidth > 0 {
		params.Bandwidth = config.Bandwidth
	}

	// 创建超时上下文
	migCtx := ctx
	if config.Timeout > 0 {
		var cancel context.CancelFunc
		migCtx, cancel = context.WithTimeout(ctx, config.Timeout)
		defer cancel()
	}

	// 启动迁移监控
	done := make(chan error, 1)
	go s.monitorMigration(migCtx, dom, job, done)

	// 执行迁移
	_, err := dom.Migrate3(nil, params, flags)

	// 等待监控完成
	<-done

	if err != nil {
		s.logger.WithError(err).Error("Migration failed")
		s.updateJobStatus(job.ID, domain.MigrationStatusFailed, err)
		return
	}

	s.logger.WithField("vm", job.VMName).Info("Migration completed successfully")
	s.updateJobStatus(job.ID, domain.MigrationStatusCompleted, nil)
}

// monitorMigration 监控迁移进度
func (s *migrationService) monitorMigration(ctx context.Context, dom *libvirt.Domain, job *domain.MigrationJob, done chan error) {
	defer close(done)

	ticker := time.NewTicker(2 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-ctx.Done():
			done <- ctx.Err()
			return
		case <-ticker.C:
			// 获取迁移统计信息
			stats, err := dom.GetJobStats(libvirt.DOMAIN_JOB_STATS_COMPLETED)
			if err != nil {
				continue
			}

			// 更新任务进度
			s.jobsMu.Lock()
			if stats.DataTotal > 0 {
				job.Progress = float64(stats.DataProcessed) / float64(stats.DataTotal) * 100
			}
			job.DataTotal = stats.DataTotal
			job.DataRemaining = stats.DataRemaining
			job.MemTotal = stats.MemTotal
			job.MemRemaining = stats.MemRemaining
			s.jobsMu.Unlock()

			// 检查是否完成
			if stats.Type == libvirt.DOMAIN_JOB_COMPLETED {
				return
			}
		}
	}
}

// GetMigrationStatus 获取迁移状态
func (s *migrationService) GetMigrationStatus(ctx context.Context, jobID string) (*domain.MigrationJob, error) {
	s.jobsMu.RLock()
	defer s.jobsMu.RUnlock()

	job, exists := s.jobs[jobID]
	if !exists {
		return nil, fmt.Errorf("migration job not found")
	}

	return job, nil
}

// CancelMigration 取消迁移
func (s *migrationService) CancelMigration(ctx context.Context, jobID string) error {
	s.jobsMu.RLock()
	job, exists := s.jobs[jobID]
	s.jobsMu.RUnlock()

	if !exists {
		return fmt.Errorf("migration job not found")
	}

	if job.Status != domain.MigrationStatusRunning {
		return fmt.Errorf("cannot cancel migration in status: %s", job.Status)
	}

	// 获取源连接和域
	srcConn, err := s.connMgr.GetConnection(job.SourceURI)
	if err != nil {
		return fmt.Errorf("failed to get source connection: %w", err)
	}

	dom, err := srcConn.LookupDomainByName(job.VMName)
	if err != nil {
		return fmt.Errorf("VM not found: %w", err)
	}
	defer dom.Free()

	// 中止迁移
	if err := dom.AbortJob(); err != nil {
		return fmt.Errorf("failed to abort migration: %w", err)
	}

	s.updateJobStatus(jobID, domain.MigrationStatusCancelled, nil)
	s.logger.WithField("job_id", jobID).Info("Migration cancelled")

	return nil
}

// ExportVM 导出虚拟机（离线迁移）
func (s *migrationService) ExportVM(ctx context.Context, connID, vmName, exportPath string) error {
	s.logger.WithFields(logrus.Fields{
		"vm":          vmName,
		"export_path": exportPath,
	}).Info("Exporting VM")

	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return err
	}

	dom, err := conn.LookupDomainByName(vmName)
	if err != nil {
		return fmt.Errorf("VM not found: %w", err)
	}
	defer dom.Free()

	// 确保虚拟机已关闭
	state, _, err := dom.GetState()
	if err != nil {
		return fmt.Errorf("failed to get VM state: %w", err)
	}
	if state != libvirt.DOMAIN_SHUTOFF {
		return fmt.Errorf("VM must be shut off before export")
	}

	// 获取虚拟机 XML
	xmlData, err := dom.GetXMLDesc(0)
	if err != nil {
		return fmt.Errorf("failed to get VM XML: %w", err)
	}

	// TODO: 实现实际的导出逻辑
	// 1. 保存 XML 到文件
	// 2. 复制所有磁盘文件
	// 3. 创建 OVF/OVA 包（可选）

	s.logger.WithField("vm", vmName).Info("VM exported successfully")
	_ = xmlData // 使用 xmlData

	return nil
}

// ImportVM 导入虚拟机
func (s *migrationService) ImportVM(ctx context.Context, connID, importPath string) (*domain.VMInfo, error) {
	s.logger.WithField("import_path", importPath).Info("Importing VM")

	conn, err := s.connMgr.GetConnection(connID)
	if err != nil {
		return nil, err
	}

	// TODO: 实现实际的导入逻辑
	// 1. 读取 XML 配置
	// 2. 复制磁盘文件到目标位置
	// 3. 更新 XML 中的路径
	// 4. 定义虚拟机

	_ = conn // 使用 conn

	return nil, fmt.Errorf("import not yet implemented")
}

// === 辅助方法 ===

func (s *migrationService) buildMigrationFlags(config *domain.MigrationConfig) libvirt.DomainMigrateFlags {
	var flags libvirt.DomainMigrateFlags

	if config.Live {
		flags |= libvirt.MIGRATE_LIVE
	}
	if config.Persistent {
		flags |= libvirt.MIGRATE_PERSIST_DEST
	}
	if config.Undefine {
		flags |= libvirt.MIGRATE_UNDEFINE_SOURCE
	}
	if config.Offline {
		flags |= libvirt.MIGRATE_OFFLINE
	}
	if config.Compressed {
		flags |= libvirt.MIGRATE_COMPRESSED
	}
	if config.Tunnelled {
		flags |= libvirt.MIGRATE_TUNNELLED
	}
	if config.SharedStorage {
		flags |= libvirt.MIGRATE_NON_SHARED_DISK
	}
	if config.AutoConverge {
		flags |= libvirt.MIGRATE_AUTO_CONVERGE
	}
	if config.PostCopy {
		flags |= libvirt.MIGRATE_POSTCOPY
	}
	if config.Parallel > 0 {
		flags |= libvirt.MIGRATE_PARALLEL
	}

	// 如果没有设置任何标志，至少设置为实时迁移
	if flags == 0 {
		flags = libvirt.MIGRATE_LIVE
	}

	return flags
}

func (s *migrationService) updateJobStatus(jobID string, status domain.MigrationStatus, err error) {
	s.jobsMu.Lock()
	defer s.jobsMu.Unlock()

	if job, exists := s.jobs[jobID]; exists {
		job.Status = status
		if status == domain.MigrationStatusCompleted || status == domain.MigrationStatusFailed || status == domain.MigrationStatusCancelled {
			now := time.Now()
			job.EndTime = &now
			if status == domain.MigrationStatusCompleted {
				job.Progress = 100
			}
		}
		if err != nil {
			job.Error = err.Error()
		}
	}
}
